from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from typing import List

from api.database import get_db
from api.model.user import User
from api.model.proxy import Proxy
from api.model.email_account import EmailAccount
from api.controller.auth import get_current_user
from api.schemas.proxy import ProxyCreate, ProxyUpdate, ProxyResponse, ProxyCreateFromV2Ray
from api.service.proxy_service import ProxyService
from api.utils.response import success, fail
from api.utils.logger import get_logger
from api.utils.helpers import get_beijing_time
from api.utils.v2ray_parser import V2RayParser
from api.utils.async_helper import run_in_executor

logger = get_logger("proxies")
router = APIRouter()

@router.get("", response_model=dict)
async def get_proxies(
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """获取当前用户的所有代理（包括自己的和别人共享的）"""
    try:
        # 获取自己的代理和别人共享的代理
        proxies = db.query(Proxy).filter(
            (Proxy.user_id == current_user.id) | (Proxy.is_shared == True)
        ).all()
        proxy_list = []
        
        # 为每个代理生成响应，V2Ray类型的代理附加配置链接
        v2ray_types = ['vmess', 'vless', 'trojan', 'shadowsocks', 'hysteria', 'hysteria2']
        for p in proxies:
            proxy_dict = ProxyResponse.from_orm(p).dict()
            
            # 判断是否为本人的代理
            is_own = p.user_id == current_user.id
            
            # 如果不是本人的代理，移除敏感信息
            if not is_own:
                proxy_dict['username'] = None
                proxy_dict['password'] = None
                proxy_dict['v2ray_config'] = None
                proxy_dict['config_link'] = None
            else:
                # 如果是V2Ray类型且有配置，生成配置链接
                if p.type in v2ray_types and p.v2ray_config:
                    try:
                        config = V2RayParser.json_to_config(p.v2ray_config)
                        success_flag, link, _ = V2RayParser.config_to_link(p.type, config)
                        if success_flag:
                            proxy_dict['config_link'] = link
                    except Exception as e:
                        logger.warning(f"生成代理 {p.name} 的配置链接失败: {e}")
                        proxy_dict['config_link'] = None
            
            proxy_list.append(proxy_dict)
        
        return success(proxy_list)
    except Exception as e:
        logger.error(f"获取代理列表失败: {e}", exc_info=True)
        return fail("获取代理列表失败")

@router.get("/{proxy_id}/export-link", response_model=dict)
async def export_proxy_link(
    proxy_id: int,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """导出代理配置为链接格式"""
    try:
        proxy = db.query(Proxy).filter(
            Proxy.id == proxy_id,
            Proxy.user_id == current_user.id
        ).first()
        
        if not proxy:
            return fail("代理不存在")
        
        # 只有v2ray类型的代理才能导出为链接
        v2ray_types = ['vmess', 'vless', 'trojan', 'shadowsocks', 'hysteria', 'hysteria2']
        if proxy.type not in v2ray_types:
            return fail(f"{proxy.type.upper()}代理不支持导出为链接")
        
        if not proxy.v2ray_config:
            return fail("代理配置不完整，无法导出")
        
        # 解析配置并转换为链接
        config = V2RayParser.json_to_config(proxy.v2ray_config)
        success_flag, link, message = V2RayParser.config_to_link(proxy.type, config)
        
        if success_flag:
            return success({"link": link}, msg="导出成功")
        else:
            return fail(f"导出失败: {message}")
            
    except Exception as e:
        logger.error(f"导出代理链接失败: {e}", exc_info=True)
        return fail(f"导出失败: {str(e)}")

@router.post("", response_model=dict)
async def create_proxy(
    proxy: ProxyCreate,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """创建新代理"""
    try:
        # 检查是否已存在同名代理
        existing = db.query(Proxy).filter(
            Proxy.user_id == current_user.id,
            Proxy.name == proxy.name
        ).first()
        
        if existing:
            return fail("代理名称已存在")
        
        db_proxy = Proxy(
            user_id=current_user.id,
            **proxy.dict()
        )
        db.add(db_proxy)
        db.commit()
        db.refresh(db_proxy)
        
        # 如果是需要 Sing-box 的代理类型，重新生成配置并重载
        singbox_protocols = ['vmess', 'vless', 'trojan', 'shadowsocks', 'hysteria', 'hysteria2', 'tuic', 'wireguard']
        if db_proxy.type in singbox_protocols and db_proxy.v2ray_config:
            logger.info(f"代理 {db_proxy.name} 创建成功，正在重新生成 Sing-box 配置...")
            from api.service.singbox_config_manager import SingBoxConfigManager
            success_count, fail_count = await run_in_executor(
                SingBoxConfigManager.restore_proxy_configs,
                db
            )
            if success_count > 0 or fail_count == 0:
                logger.info(f"Sing-box 配置已更新并重载")
            else:
                logger.warning(f"Sing-box 配置重载失败")
        
        return success(ProxyResponse.from_orm(db_proxy), msg="代理添加成功")
    except Exception as e:
        db.rollback()
        logger.error(f"创建代理失败: {e}", exc_info=True)
        return fail(f"创建代理失败: {str(e)}")

@router.post("/import-v2ray", response_model=dict)
async def import_v2ray_proxy(
    v2ray_data: ProxyCreateFromV2Ray,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """从V2Ray链接导入代理配置"""
    try:
        # 解析v2ray链接
        success_flag, config, message = V2RayParser.parse_v2ray_link(v2ray_data.v2ray_link)
        
        if not success_flag:
            return fail(f"解析V2Ray链接失败: {message}")
        
        # 检查是否已存在同名代理
        existing = db.query(Proxy).filter(
            Proxy.user_id == current_user.id,
            Proxy.name == config['name']
        ).first()
        
        if existing:
            # 自动添加后缀避免重名
            import time
            config['name'] = f"{config['name']}_{int(time.time())}"
        
        # 转换配置为JSON字符串
        v2ray_config_json = V2RayParser.config_to_json(config.get('full_config', {}))
        
        # 创建代理记录
        db_proxy = Proxy(
            user_id=current_user.id,
            name=config['name'],
            type=config['type'],
            host=config['host'],
            port=config['port'],
            username=config.get('uuid', config.get('username')),  # vmess/vless使用uuid
            password=config.get('password'),
            v2ray_config=v2ray_config_json
        )
        db.add(db_proxy)
        db.commit()
        db.refresh(db_proxy)
        
        logger.info(f"成功从V2Ray链接导入代理: {config['name']} ({config['type']})")
        
        # 重新生成 Sing-box 配置并重载
        if v2ray_config_json:
            logger.info(f"代理 {config['name']} 导入成功，正在重新生成 Sing-box 配置...")
            from api.service.singbox_config_manager import SingBoxConfigManager
            success_count, fail_count = await run_in_executor(
                SingBoxConfigManager.restore_proxy_configs,
                db
            )
            if success_count > 0 or fail_count == 0:
                logger.info(f"Sing-box 配置已更新并重载")
            else:
                logger.warning(f"Sing-box 配置重载失败")
        
        return success(ProxyResponse.from_orm(db_proxy), msg=f"成功导入{config['type'].upper()}代理")
        
    except Exception as e:
        db.rollback()
        logger.error(f"导入V2Ray代理失败: {e}", exc_info=True)
        return fail(f"导入代理失败: {str(e)}")

@router.post("/{proxy_id}/test", response_model=dict)
async def test_proxy(
    proxy_id: int,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """测试代理延迟"""
    try:
        proxy = db.query(Proxy).filter(
            Proxy.id == proxy_id,
            Proxy.user_id == current_user.id
        ).first()
        
        if not proxy:
            return fail("代理不存在")
        
        # 对于需要Sing-box的代理类型，检查是否已安装
        singbox_protocols = ['vmess', 'vless', 'trojan', 'shadowsocks', 'hysteria', 'hysteria2', 'tuic', 'wireguard']
        if proxy.type in singbox_protocols:
            from api.service.singbox_manager import SingBoxManager
            installed, version = await run_in_executor(SingBoxManager.check_singbox_installed)
            if not installed:
                return fail(f"使用{proxy.type.upper()}代理需要先安装Sing-box内核，请前往'Sing-box管理'进行安装")
        
        logger.info(f"开始测试代理: {proxy.name} ({proxy.type}://{proxy.host}:{proxy.port})")
        
        # 测试代理延迟（增加到30秒超时） - 异步执行
        success_flag, latency, message = await run_in_executor(
            ProxyService.test_proxy_latency,
            proxy.type,
            proxy.host,
            proxy.port,
            proxy.username,
            proxy.password,
            v2ray_config=proxy.v2ray_config,
            timeout=30
        )
        
        if success_flag:
            # 更新代理延迟和测试时间
            proxy.latency = latency
            proxy.last_test_time = get_beijing_time()
            db.commit()
            
            if latency > 0:
                return success({"latency": latency}, msg=f"测试成功，延迟: {latency}ms")
            else:
                return success({"latency": latency}, msg=message)
        else:
            return fail(message)
            
    except Exception as e:
        logger.error(f"测试代理时出错: {e}", exc_info=True)
        return fail(f"测试代理失败: {str(e)}")

@router.put("/{proxy_id}", response_model=dict)
async def update_proxy(
    proxy_id: int,
    proxy_update: ProxyUpdate,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """更新代理配置"""
    try:
        proxy = db.query(Proxy).filter(Proxy.id == proxy_id).first()
        
        if not proxy:
            return fail("代理不存在")
        
        # 检查权限：只能修改自己的代理
        if proxy.user_id != current_user.id:
            return fail("无权修改他人共享的代理")
        
        # 如果修改名称，检查是否重名
        if proxy_update.name and proxy_update.name != proxy.name:
            existing = db.query(Proxy).filter(
                Proxy.user_id == current_user.id,
                Proxy.name == proxy_update.name,
                Proxy.id != proxy_id
            ).first()
            if existing:
                return fail("代理名称已存在")
        
        # 记录是否是 Sing-box 代理类型
        singbox_protocols = ['vmess', 'vless', 'trojan', 'shadowsocks', 'hysteria', 'hysteria2', 'tuic', 'wireguard']
        is_singbox_proxy = proxy.type in singbox_protocols and proxy.v2ray_config
        
        # 更新字段
        update_data = proxy_update.dict(exclude_unset=True)
        for field, value in update_data.items():
            setattr(proxy, field, value)
        
        db.commit()
        db.refresh(proxy)
        
        # 如果是 Sing-box 代理，重新生成配置并重载
        if is_singbox_proxy:
            logger.info(f"代理 {proxy.name} 更新成功，正在重新生成 Sing-box 配置...")
            from api.service.singbox_config_manager import SingBoxConfigManager
            success_count, fail_count = await run_in_executor(
                SingBoxConfigManager.restore_proxy_configs,
                db
            )
            if success_count > 0 or fail_count == 0:
                logger.info(f"Sing-box 配置已更新并重载")
            else:
                logger.warning(f"Sing-box 配置重载失败")
        
        return success(ProxyResponse.from_orm(proxy), msg="代理更新成功")
    except Exception as e:
        db.rollback()
        logger.error(f"更新代理失败: {e}", exc_info=True)
        return fail(f"更新代理失败: {str(e)}")

@router.delete("/{proxy_id}", response_model=dict)
async def delete_proxy(
    proxy_id: int,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """删除代理"""
    try:
        proxy = db.query(Proxy).filter(Proxy.id == proxy_id).first()
        
        if not proxy:
            return fail("代理不存在")
        
        # 检查权限：只能删除自己的代理
        if proxy.user_id != current_user.id:
            return fail("无权删除他人共享的代理")
        
        # 检查是否有邮箱账户正在使用此代理
        using_accounts = db.query(EmailAccount).filter(
            EmailAccount.proxy_id == proxy_id
        ).all()
        
        if using_accounts:
            # 区分本人和他人的邮箱账户
            my_accounts = [acc for acc in using_accounts if acc.user_id == current_user.id]
            other_accounts = [acc for acc in using_accounts if acc.user_id != current_user.id]
            
            if my_accounts and other_accounts:
                my_emails = ", ".join([acc.email for acc in my_accounts])
                return fail(f"有邮箱账户正在使用此代理，无法删除。您的邮箱: {my_emails}；另有 {len(other_accounts)} 个其他用户的邮箱在使用")
            elif my_accounts:
                my_emails = ", ".join([acc.email for acc in my_accounts])
                return fail(f"以下邮箱账户正在使用此代理，无法删除: {my_emails}")
            else:
                return fail(f"有 {len(other_accounts)} 个其他用户的邮箱正在使用此代理，无法删除")
        
        # 记录是否是 Sing-box 代理类型
        singbox_protocols = ['vmess', 'vless', 'trojan', 'shadowsocks', 'hysteria', 'hysteria2', 'tuic', 'wireguard']
        is_singbox_proxy = proxy.type in singbox_protocols and proxy.v2ray_config
        
        proxy_name = proxy.name
        db.delete(proxy)
        db.commit()
        
        # 如果是 Sing-box 代理，重新生成配置并重载
        if is_singbox_proxy:
            logger.info(f"代理 {proxy_name} 删除成功，正在重新生成 Sing-box 配置...")
            from api.service.singbox_config_manager import SingBoxConfigManager
            success_count, fail_count = await run_in_executor(
                SingBoxConfigManager.restore_proxy_configs,
                db
            )
            if success_count >= 0:  # 删除后可能没有代理了，所以 success_count 可能为 0
                logger.info(f"Sing-box 配置已更新并重载")
            else:
                logger.warning(f"Sing-box 配置重载失败")
        
        return success(msg="代理删除成功")
    except Exception as e:
        db.rollback()
        logger.error(f"删除代理失败: {e}", exc_info=True)
        return fail(f"删除代理失败: {str(e)}")

@router.post("/{proxy_id}/toggle-share", response_model=dict)
async def toggle_proxy_share(
    proxy_id: int,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """切换代理的共享状态"""
    try:
        proxy = db.query(Proxy).filter(Proxy.id == proxy_id).first()
        
        if not proxy:
            return fail("代理不存在")
        
        # 检查权限：只能操作自己的代理
        if proxy.user_id != current_user.id:
            return fail("无权操作他人的代理")
        
        new_share_status = not proxy.is_shared
        
        # 如果是取消共享，需要清除其他用户邮箱账号的代理关联
        if not new_share_status:
            db.query(EmailAccount).filter(
                EmailAccount.proxy_id == proxy_id,
                EmailAccount.user_id != current_user.id # 仅清除其他用户的
            ).update({"proxy_id": None})
            
        proxy.is_shared = new_share_status
        db.commit()
        db.refresh(proxy)
        
        status_text = "已共享" if proxy.is_shared else "已取消共享"
        return success(ProxyResponse.from_orm(proxy), msg=f"代理{status_text}")
    except Exception as e:
        db.rollback()
        logger.error(f"切换代理共享状态失败: {e}", exc_info=True)
        return fail(f"操作失败: {str(e)}")